﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DotNetCommon;
using DotNetCommon.Data;
using DotNetCommon.Extensions;
using System.Data.Common;
using System.Reflection;
using System.Linq.Expressions;
using DotNetCommon.Logger;
using System.Text;
using System.Diagnostics;

namespace DBUtil
{
    /// <summary>
    /// 通用数据库访问对象
    /// </summary>
    public abstract partial class DBAccess
    {
        #region 执行sql语句 ExecuteSql...
        public virtual async Task<int> ExecuteSqlAsync(string strSql, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(strSql, null, null, new DbParameter[0], cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string strSql, IDictionary<string, object> dic, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(strSql, null, null, dic?.Keys.Select(key => CreatePara(key, dic[key])).ToArray(), cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await ExecuteSqlAsync(strSql, null, null, parameters, cancellationToken);

        public virtual async Task<int> ExecuteSqlAsync(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            var cmd = createCommand(commandType, timeout, strSql, parameters);
            return await RunInConnectionAsync(async () =>
            {
                var res = await cmd.ExecuteNonQueryAsync(cancellationToken);
                cmd.Parameters?.Clear();
                return res;
            });
        }
        #endregion

        #region Insert...
        /// <summary>
        /// 向一个表插入一行,示例：
        /// <list type="number">
        /// <item>InsertAsync("test", new { name = "小明" }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public virtual async Task<int> InsertAsync(string tableName, IDictionary<string, object> dic, CancellationToken cancellationToken = default)
            => await InsertAsync(tableName, new IDictionary<string, object>[] { dic }, cancellationToken);

        /// <summary>
        /// 向一个表批量插入,示例：
        /// <list type="number">
        /// <item> InsertAsync("test", new IDictionary&lt;string, object>[] { new { name = "小明" }.ToDictionary(), new { name = "小王", age = 18 }.ToDictionary() });</item>
        /// </list>
        /// </summary>
        public virtual async Task<int> InsertAsync(string tableName, IDictionary<string, object>[] dics, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = InsertToSql(tableName, dics);
            return await ExecuteSqlAsync(sql, paras);
        }

        /// <summary>
        /// 批量插入数据(可批量向不同表插入),示例：
        /// <list type="number">
        /// <item>InsertBatchAsync(new InsertBatchItem[]{InsertBatchItem.Create("test1", new { name = "小明" }.ToDictionary()), InsertBatchItem.Create("test2", new { name = "小王", age = 18 }.ToDictionary())})</item>
        /// </list>
        /// </summary>
        public virtual async Task<int> InsertBatchAsync(InsertBatchItem[] items, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = InsertBatchToSql(items);
            return await ExecuteSqlAsync(sql, paras);
        }

        /// <summary>
        /// 插入一行数据并且返回自增的Id（也可以是来自序列的自增id），示例：
        /// <list type="number">
        /// <item>var id = await InsertAndGetIdAsync("test", new { name="小明"}.ToDictionary())</item>
        /// </list>
        /// </summary>
        public virtual async Task<long> InsertAndGetIdAsync(string tableName, IDictionary<string, object> dic, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = InsertAndGetIdToSql(tableName, dic);
            return await SelectScalarAsync<long>(sql, paras);
        }

        /// <summary>
        /// 插入多行数据(相同表)并且返回自增的Id集合,认为自增步长为1，示例：
        /// <list type="number">
        /// <item>var ids = await InsertAndGetIdsAsync("test", new IDictionary&lt;string, object>[] { new { name = "小明" }.ToDictionary(), new { name = "小王" }.ToDictionary() });</item>
        /// </list>
        /// </summary>
        public virtual async Task<List<long>> InsertAndGetIdsAsync(string tableName, IDictionary<string, object>[] dics, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = InsertAndGetIdsToSql(tableName, dics);
            var id = await SelectScalarAsync<long>(sql, paras);
            var ids = new List<long>();
            //假设id自增为1,比如: 基础为1,插入三条(id=2,3,4),返回:4, 最终计算出: [2,3,4]
            for (int i = 0, len = dics.Length; i < len; i++)
            {
                ids.Add(id - len + i + 1);
            }
            return ids;
        }
        #endregion

        #region Update...

        /// <summary>
        /// 更新数据,示例：
        /// <list type="number">
        /// <item>UpdateAsync("test", new { name = "小明" }.ToDictionary(), "and id=1",null);</item>
        /// <item>UpdateAsync("test", new { name = "小明" }.ToDictionary(), "and id=@id", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> UpdateAsync(string tableName, IDictionary<string, object> setDic, string whereSql, IDictionary<string, object> parameters = null, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = UpdateToSql(UpdateBatchItem.Create(tableName, setDic, whereSql, parameters));
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }

        /// <summary>
        /// 更新数据，示例：
        /// <list type="number">
        /// <item>UpdateAsync("test", new { name = "小明" }.ToDictionary(),  new { id = 1 }.ToDictionary())</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> UpdateAsync(string tableName, IDictionary<string, object> setDic, IDictionary<string, object> whereDic, CancellationToken cancellationToken = default)
        {
            var (sql, paras) = UpdateToSql(UpdateBatchItem.Create(tableName, setDic, whereDic));
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }

        /// <summary>
        /// 批量更新,不同表，示例：
        /// <list type="number">
        /// <item>UpdateBatchAsync(new UpdateBatchItem[]{<br/>
        /// UpdateBatchItem.Create("test1", new { name = "小明" }.ToDictionary(), "and id=1"),<br/>
        /// UpdateBatchItem.Create("test2", new { name = "小明2" }.ToDictionary(), new { id = 1 }.ToDictionary())<br/>
        /// });</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> UpdateBatchAsync(UpdateBatchItem[] items, CancellationToken cancellationToken = default)
        {
            var sqls = new List<string>();
            var paras = new Dictionary<string, object>();
            foreach (var item in items)
            {
                var (sql2, para2) = UpdateToSql(item);
                sqls.Add(sql2);
                paras.Add(para2);
            }
            var sql = sqls.ToStringSeparated("\r\n");
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }
        #endregion

        #region UpdateOrInsert

        /// <summary>
        /// 插入或更新，示例：
        /// <list type="number">
        /// <item>UpdateOrInsertAsync("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), "and id=1");</item>
        /// <item>UpdateOrInsertAsync("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), "and id=@id", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> UpdateOrInsertAsync(string tableName, IDictionary<string, object> insertDic, IDictionary<string, object> updateDic, string whereSql, IDictionary<string, object> parameters = null, CancellationToken cancellationToken = default)
        {
            var filterSql = "";
            if (whereSql.IsNotNullOrEmptyOrWhiteSpace())
            {
                var t = whereSql.TrimStart(' ').ToUpper();
                if (t.StartsWith("WHERE")) filterSql = $" {whereSql.TrimStart(' ')}";
                else if (t.StartsWith("AND") || t.StartsWith("OR")) filterSql = $" where 1=1 {whereSql.TrimStart(' ')}";
                else filterSql = $" where {whereSql.TrimStart(' ')}";
            }
            if (await SelectScalarAsync<int>($"select count(1) from {tableName} {filterSql};", parameters, cancellationToken) == 0)
            {
                return await InsertAsync(tableName, insertDic, cancellationToken);
            }
            else
            {
                return await UpdateAsync(tableName, updateDic, whereSql, parameters, cancellationToken);
            }
        }

        /// <summary>
        /// 插入或更新，示例：
        /// <list type="number">
        /// <item>UpdateOrInsertAsync("test", new { id = 1, name = "小明2" }.ToDictionary(), new { name = "小明2" }.ToDictionary(), new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> UpdateOrInsertAsync(string tableName, IDictionary<string, object> insertDic, IDictionary<string, object> updateDic, IDictionary<string, object> filterDic, CancellationToken cancellationToken = default)
        {
            if (filterDic.IsNullOrEmpty()) return await UpdateOrInsertAsync(tableName, insertDic, updateDic, string.Empty, null, cancellationToken);
            var (filterSql, paras) = WhereToSql(filterDic);
            var sql = $"select count(1) from {tableName} where 1=1 {filterSql}";
            if (await SelectScalarAsync<int>(sql, paras) == 0)
            {
                return await InsertAsync(tableName, insertDic, cancellationToken);
            }
            else
            {
                return await UpdateAsync(tableName, updateDic, filterSql, paras, cancellationToken);
            }
        }
        #endregion

        #region Delete

        /// <summary>
        /// 删除数据，示例：
        /// <list type="number">
        /// <item>db.DeleteAsync("test","and id=@id",new { id=1}.ToDictionary())</item>
        /// <item>db.DeleteAsync("test","id=:id",new { id=1}.ToDictionary())</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> DeleteAsync(string tableName, string whereSql, IDictionary<string, object> parameters = null, CancellationToken cancellationToken = default)
        {
            var item = DeleteBatchItem.Create(tableName, whereSql, parameters);
            var (sql, paras) = DeleteToSql(item);
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }

        /// <summary>
        /// 删除数据，示例：
        /// <list type="number">
        /// <item>db.DeleteAsync("test", new { id = 1 }.ToDictionary());</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> DeleteAsync(string tableName, IDictionary<string, object> whereDic, CancellationToken cancellationToken = default)
        {
            var item = DeleteBatchItem.Create(tableName, whereDic);
            var (sql, paras) = DeleteToSql(item);
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }

        /// <summary>
        /// 批量删除(不同表)，示例：
        /// <list type="number">
        /// <item>db.DeleteBatchAsync(DeleteBatchItem.Create("test1", "and id=1"), DeleteBatchItem.Create("test2", new { id = 2 }.ToDictionary()));</item>
        /// </list>
        /// </summary>
        public async virtual Task<int> DeleteBatchAsync(DeleteBatchItem[] items, CancellationToken cancellationToken = default)
        {
            var sqls = new List<string>();
            var paras = new Dictionary<string, object>();
            for (var i = 0; i < items.Length; i++)
            {
                var (sql2, para2) = DeleteToSql(items[i]);
                sqls.Add(sql2);
                if (para2.IsNotNullOrEmpty()) paras.Add(para2);
            }
            var sql = sqls.ToStringSeparated("\r\n");
            return await ExecuteSqlAsync(sql, paras, cancellationToken);
        }
        #endregion

        #region 查询语句 Select...

        #region SelectScalarAsync
        public async virtual Task<T> SelectScalarAsync<T>(string strSql, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(strSql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string strSql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectScalarAsync<T>(strSql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectScalarAsync<T>(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            var cmd = createCommand(commandType, timeout, strSql, parameters);
            return await RunInConnectionAsync(async () =>
            {
                var res = await cmd.ExecuteScalarAsync(cancellationToken);
                cmd.Parameters?.Clear();
                return res.To<T>();
            });
        }
        #endregion

        #region SelectDataSetAsync
        public virtual async Task<DataSet> SelectDataSetAsync(string strSql, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(strSql, null, null, null, cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(strSql, null, null, parameters, cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string strSql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataSetAsync(strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public virtual async Task<DataSet> SelectDataSetAsync(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
            {
                DataSet set = new DataSet();
                do
                {
                    var dt = new DataTable();
                    var count = reader.FieldCount;
                    for (int i = 0; i < count; i++)
                    {
                        dt.Columns.Add(new DataColumn(reader.GetName(i), reader.GetFieldType(i)));
                    }
                    while (await reader.ReadAsync())
                    {
                        var arr = new object[count];
                        reader.GetValues(arr);
                        dt.Rows.Add(arr);
                    }
                    set.Tables.Add(dt);
                } while (await reader.NextResultAsync());
                return set;
            }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #region SelectDataTableAsync
        public virtual async Task<DataTable> SelectDataTableAsync(string strSql, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(strSql, null, null, null, cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string strSql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDataTableAsync(strSql, null, null, parameters, cancellationToken);

        public virtual async Task<DataTable> SelectDataTableAsync(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
             {
                 var dt = new DataTable();
                 var count = reader.FieldCount;
                 for (int i = 0; i < count; i++)
                 {
                     dt.Columns.Add(new DataColumn(reader.GetName(i), reader.GetFieldType(i)));
                 }
                 while (await reader.ReadAsync())
                 {
                     var arr = new object[count];
                     reader.GetValues(arr);
                     dt.Rows.Add(arr);
                 }
                 return dt;
             }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #region SelectDataReaderAsync

        #region SelectDataReaderAsync Action
        public async virtual Task SelectDataReaderAsync(Func<DbDataReader, Task> func, string strSql, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, null, cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DbDataReader, Task> func, string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, parameters, cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DbDataReader, Task> func, string strSql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task SelectDataReaderAsync(Func<DbDataReader, Task> func, string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            if (func == null) throw new Exception("执行的逻辑不能为空!");
            var cmd = createCommand(commandType, timeout, strSql, parameters);
            await RunInConnectionAsync(async () =>
            {
                var reader = await cmd.ExecuteReaderAsync(cancellationToken);
                readers.Push(reader);
                try
                {
                    await func.Invoke(reader);
                }
                finally
                {
                    if (!reader.IsClosed)
                        try { await reader.CloseAsync(); } catch { }
                    cmd.Parameters?.Clear();
                    readers.Pop();
                }
            });
        }
        #endregion

        #region SelectDataReaderAsync Func
        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DbDataReader, Task<T>> func, string strSql, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DbDataReader, Task<T>> func, string strSql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DbDataReader, Task<T>> func, string strSql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDataReaderAsync(func, strSql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectDataReaderAsync<T>(Func<DbDataReader, Task<T>> func, string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            if (func == null) throw new Exception("执行的逻辑不能为空!");
            var cmd = createCommand(commandType, timeout, strSql, parameters);
            return await RunInConnectionAsync(async () =>
            {
                var reader = await cmd.ExecuteReaderAsync(cancellationToken);
                readers.Push(reader);
                try
                {
                    T result = default(T);
                    result = await func(reader);
                    return result;
                }
                finally
                {
                    if (!reader.IsClosed)
                        try { await reader.CloseAsync(); } catch { }
                    cmd.Parameters?.Clear();
                    readers.Pop();
                }
            });
        }
        #endregion

        #endregion

        #region SelectModelAsync

        #region SelectModelAsync
        public async virtual Task<T> SelectModelAsync<T>(string sql, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelAsync<T>(sql, null, null, null, cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string sql, DbParameter[] parameters, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelAsync<T>(sql, null, null, parameters, cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelAsync<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<T> SelectModelAsync<T>(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default) where T : class, new()
        {
            return await SelectDataReaderAsync(async reader =>
            {
                if (!await reader.ReadAsync())
                    return null;
                var exp = GetFunc<T>(reader);
                var inst = exp(reader);
                return inst;
            }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #region SelectModelListAsync
        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelListAsync<T>(sql, null, null, null, cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, DbParameter[] parameters, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelListAsync<T>(sql, null, null, parameters, cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default) where T : class, new()
            => await SelectModelListAsync<T>(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<List<T>> SelectModelListAsync<T>(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default) where T : class, new()
        {
            return await SelectDataReaderAsync(async reader =>
            {
                var list = new List<T>();
                var exp = GetFunc<T>(reader);
                while (await reader.ReadAsync())
                {
                    var inst = exp(reader);
                    list.Add(inst);
                }
                return list;
            }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #endregion

        #region SelectDictionaryAsync

        #region SelectDictionaryAsync
        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, null, cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, parameters, cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<Dictionary<string, object>> SelectDictionaryAsync(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
            {
                Dictionary<string, object> dic = null;
                var count = reader.FieldCount;
                if (await reader.ReadAsync())
                {
                    dic = new Dictionary<string, object>();
                    for (int i = 0; i < count; i++)
                    {
                        dic[reader.GetName(i)] = reader.GetValue(i);
                    }
                }
                return dic;
            }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #region SelectDictionaryListAsync
        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, null, cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, DbParameter[] parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, parameters, cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string sql, IDictionary<string, object> parameters, CancellationToken cancellationToken = default)
            => await SelectDictionaryListAsync(sql, null, null, parameters?.Select(x => CreatePara(x.Key, x.Value)).ToArray(), cancellationToken);

        public async virtual Task<List<Dictionary<string, object>>> SelectDictionaryListAsync(string strSql, CommandType? commandType, int? timeout, DbParameter[] parameters, CancellationToken cancellationToken = default)
        {
            return await SelectDataReaderAsync(async reader =>
            {
                var count = reader.FieldCount;
                var names = new string[count];
                for (int i = 0; i < count; i++)
                {
                    names[i] = reader.GetName(i);
                }
                var list = new List<Dictionary<string, object>>();
                while (await reader.ReadAsync())
                {
                    var dic = new Dictionary<string, object>();
                    list.Add(dic);
                    for (int i = 0; i < count; i++)
                    {
                        dic[names[i]] = reader.GetValue(i);
                    }
                }
                return list;
            }, strSql, commandType, timeout, parameters, cancellationToken);
        }
        #endregion

        #endregion

        #endregion
    }
}
